﻿using System;
using System.Collections.Generic;
using checc_baseTools.CaveMouth.Entity;
using Culvert_Help;
using NeXus.BIMBase;
using NeXus.BIMBase.Core;
using NeXus.BIMBase.SolidCore;
using NeXus.p3d;
using static NeXus.p3d.GeCurveArray;

namespace checc_baseTools.CaveMouth
{
    public class Gutter
    {
        /// <summary>
        /// 排水槽整体
        /// </summary>
        /// <param name="gutter">排水槽实例</param>
        /// <param name="culvertWidth">净跨</param>
        /// <param name="coverThickness">盖板厚度</param>
        /// <param name="angle">洞口交角</param>
        /// <returns></returns>
        public static BPGraphicsCollection CreateEntityModel(GutterData gutterData, double culvertWidth, double angle)
        {
            GutterData gutter = new GutterData();
            gutter.HighEndHeight = gutterData.HighEndHeight * Culvert_Help.GeneralHelpers.UOR;
            gutter.LowSideHeight = gutterData.LowSideHeight * Culvert_Help.GeneralHelpers.UOR;
            gutter.RhoneLength = gutterData.RhoneLength * Culvert_Help.GeneralHelpers.UOR;
            gutter.OpeningSlope = gutterData.OpeningSlope;
            gutter.TopWidth = gutterData.TopWidth * Culvert_Help.GeneralHelpers.UOR;
            gutter.UnilateralWidth = gutterData.UnilateralWidth * Culvert_Help.GeneralHelpers.UOR;
            gutter.InsideSlope = gutterData.InsideSlope;
            gutter.OutsideSlope = gutterData.OutsideSlope;
            gutter.TankBottomHeight = gutterData.TankBottomHeight * Culvert_Help.GeneralHelpers.UOR;
            culvertWidth = culvertWidth * Culvert_Help.GeneralHelpers.UOR;
            //计算底面外坡长度
            double bottomWidthLeft_R = gutter.OutsideSlope == 0 ? 0 : gutter.HighEndHeight * gutter.OutsideSlope;
            //double rightAngleSide = bottomWidthLeft_R / Math.Cos((90 - angle) / 180 * Math.PI);
            // rightAngleSide += gutter.TopWidth / Math.Cos((90 - angle) / 180 * Math.PI);
            //计算底面内坡长度
            double bottomWidthRight_R = gutter.InsideSlope == 0 ? 0 : gutter.HighEndHeight * gutter.InsideSlope;
            //rightAngleSide += bottomWidthRight_R / Math.Cos((90 - angle) / 180 * Math.PI);
            //底面宽度 = 内坡 +外坡 + 顶面宽度 
            double rightAngleSide = bottomWidthLeft_R + bottomWidthRight_R + gutter.TopWidth;
            //槽底
            GePoint3dCollection tankBottomTopGePoint3ds = GetTankBottomPoints(gutter.TankBottomHeight, gutter.UnilateralWidth * 2 + culvertWidth + 2 * rightAngleSide, gutter.RhoneLength, gutter.OpeningSlope, angle);
            //创建右侧翼墙
            (BPGraphics, GePoint3d) CulvertRhoneBody_R = CreateRightCulvertRhoneBody(tankBottomTopGePoint3ds, gutter.HighEndHeight, gutter.LowSideHeight, gutter.TopWidth, gutter.InsideSlope, gutter.OutsideSlope, gutter.TankBottomHeight, angle);
            //创建左侧翼墙
            (BPGraphics, GePoint3d) CulvertRhoneBody_L = CreateLeftCulvertRhoneBody(tankBottomTopGePoint3ds, gutter.HighEndHeight, gutter.LowSideHeight, gutter.TopWidth, gutter.InsideSlope, gutter.OutsideSlope, gutter.TankBottomHeight, angle);
            //获取翼墙实例
            BPGraphics CulvertRhoneBodyElement_L = CulvertRhoneBody_L.Item1;
            BPGraphics CulvertRhoneBodyElement_R = CulvertRhoneBody_R.Item1;
            //修改槽底顶面点位 梯形
            tankBottomTopGePoint3ds[0] = new GePoint3d(tankBottomTopGePoint3ds[0].x, tankBottomTopGePoint3ds[0].y, tankBottomTopGePoint3ds[0].z);
            tankBottomTopGePoint3ds[1] = new GePoint3d(tankBottomTopGePoint3ds[1].x, tankBottomTopGePoint3ds[1].y, tankBottomTopGePoint3ds[1].z);

            tankBottomTopGePoint3ds[2] = new GePoint3d(CulvertRhoneBody_L.Item2.x, CulvertRhoneBody_L.Item2.y, CulvertRhoneBody_L.Item2.z);
            tankBottomTopGePoint3ds[3] = new GePoint3d(CulvertRhoneBody_R.Item2.x, CulvertRhoneBody_R.Item2.y, CulvertRhoneBody_R.Item2.z);
            //底面
            GePoint3dCollection tankBottomBottomGePoint3ds = new GePoint3dCollection()
            {
                new GePoint3d(tankBottomTopGePoint3ds[0].x, tankBottomTopGePoint3ds[0].y, tankBottomTopGePoint3ds[0].z - gutter.TankBottomHeight),
                new GePoint3d(tankBottomTopGePoint3ds[1].x, tankBottomTopGePoint3ds[1].y, tankBottomTopGePoint3ds[1].z - gutter.TankBottomHeight),
                new GePoint3d(tankBottomTopGePoint3ds[2].x, tankBottomTopGePoint3ds[2].y, tankBottomTopGePoint3ds[2].z - gutter.TankBottomHeight),
                new GePoint3d(tankBottomTopGePoint3ds[3].x, tankBottomTopGePoint3ds[3].y, tankBottomTopGePoint3ds[3].z - gutter.TankBottomHeight),
            };
            //创建槽底
            BPGraphics tankBottom = Create(tankBottomTopGePoint3ds, tankBottomBottomGePoint3ds);
            //翼墙合集
            BPGraphics wingWall = Element_solid.BoolCollection(CulvertRhoneBodyElement_R, CulvertRhoneBodyElement_L, false);
            //graphics.save();

            //返回锥坡底面四个点的平面
            GeCurveArray geCurveArray = GeCurveArray.createLinestringArray(tankBottomBottomGePoint3ds, BoundaryType.BOUNDARY_TYPE_Outer, true);
            BPGraphics plan = GeneralHelpers.Model2D.createPhysicalGraphics();
            plan.addCurveArray(geCurveArray);
            //plan = Helper.unitRotation(plan, angle);
            return new BPGraphicsCollection { tankBottom, wingWall, plan };

            ////构建顶面
            //GeCurveArray curveArraytop = GeCurveArray.createLinestringArray(tankBottomTopGePoint3ds, BoundaryType.Outer, true);
            ////体
            //GeVec3d v3d = new GeVec3d(0, 0, gutter.TankBottomHeight);
            //GeExtrusionInfo extrusionInfo = new GeExtrusionInfo(curveArraytop, v3d, true);
            //var solid = IGeSolidBase.createExtrusion(extrusionInfo);
            ////GeExtrusionInfo extrusionInfo = new GeExtrusionInfo(curveArraytop, v3d, true);
            ////IGeSolidBase solid = Elemen_solid.getTensileBody(extrusionInfo);
            //BPGraphics bPGraphics = BPApplication.getInstance().getProjectManager().getActiveModel().createPhysicalGraphics();
            //bPGraphics.addSolid(solid);
            //bPGraphics.save();
            //Elemen_solid.BoolCollection(graphics, tools, true);

            ////位移
            //GePoint3d movePt = new GePoint3d(0, 0, -gutter.TankBottomHeight) * GeneralBank.UorToMeters; ;
            //DTransform3d trans = new DTransform3d(DMatrix3d.Identity);
            //trans.Translation = movePt;
            //resultSolid.ApplyTransform(new TransformInfo(trans));
            //return resultSolid;
        }

        /// <summary>
        /// 初始化排水槽洞口参数
        /// </summary>
        /// <returns></returns>
        private static (double highEndHeight, double lowSideHeight, double rhoneLength, double openingSlope, double topWidth, double unilateralWidth, double insideSlope, double outsideSlope, double tankBottomHeight) GetUorCoverParameter()
        {
            double highEndHeight = 200;
            double lowSideHeight = 50;
            double rhoneLength = 200;
            double openingSlope = 0.01;
            double topWidth = 30;
            double unilateralWidth = 100;
            double insideSlope = 0;
            double outsideSlope = 0.25;
            double tankBottomHeight = 30;
            return (highEndHeight, lowSideHeight, rhoneLength, openingSlope, topWidth, unilateralWidth, insideSlope, outsideSlope, tankBottomHeight);
        }

        /// <summary>
        /// 创建洞口右侧翼墙
        /// </summary>
        /// <param name="tankBottomTopGePoint3ds">槽底顶面点集</param>
        /// <param name="highEndHeight">高端高度</param>
        /// <param name="lowSideHeight">低端高度</param>
        /// <param name="topWidth">顶部宽</param>
        /// <param name="insideSlope">内坡坡度</param>
        /// <param name="outsideSlope">外坡坡度</param>
        /// <param name="angle">洞口夹角</param>
        /// <returns></returns>
        private static (BPGraphics, GePoint3d) CreateRightCulvertRhoneBody(GePoint3dCollection tankBottomTopGePoint3ds, double highEndHeight, double lowSideHeight, double topWidth, double insideSlope, double outsideSlope, double tankBottomHeight, double angle)
        {
            GeSegment3d LinearElement_R = new GeSegment3d(tankBottomTopGePoint3ds[2], tankBottomTopGePoint3ds[3]);

            double bottomWidthLeft_R = outsideSlope == 0 ? 0 : highEndHeight * outsideSlope;

            #region 靠近洞口的点
            double rightAngleSide = bottomWidthLeft_R / Math.Cos((90 - angle) / 180 * Math.PI);
            //右上
            GePoint3d topRight_R = Helper.Extend_or_Contract(tankBottomTopGePoint3ds[0], tankBottomTopGePoint3ds[1], rightAngleSide);
            //左上
            rightAngleSide = topWidth / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d topLeft_R = Helper.Extend_or_Contract(topRight_R, tankBottomTopGePoint3ds[1], rightAngleSide);
            //左下
            double bottomWidthRight_R = insideSlope == 0 ? 0 : highEndHeight * insideSlope;
            rightAngleSide = bottomWidthRight_R / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d bottomLeft_R = Helper.Extend_or_Contract(topLeft_R, tankBottomTopGePoint3ds[1], rightAngleSide);
            bottomLeft_R.z = bottomLeft_R.z/* + tankBottomHeight*/;
            topRight_R.z = tankBottomTopGePoint3ds[0].z + highEndHeight;
            topLeft_R.z = tankBottomTopGePoint3ds[0].z + highEndHeight;
            //右下
            GePoint3d bottomRight_R = tankBottomTopGePoint3ds[0];
            #endregion

            #region 外侧点
            GeSegment3d TopRightLinearElement = new GeSegment3d(topRight_R, Helper.Extend_or_Contract(topRight_R, new GePoint3d(topRight_R.x + 1, topRight_R.y, topRight_R.z), 1000));
            double fractionA = 0;
            double fractionB = 0;
            GePoint3d insertDpoint = new GePoint3d(0, 0, 0);
            GePoint3d ptB = new GePoint3d(100, 0, 0);
            GeSegment3d.getIntersectPointOfTwoSegments2D(ref fractionA, ref fractionB, insertDpoint, ptB, LinearElement_R, TopRightLinearElement);
            //右上
            GePoint3d topRight_R2 = new GePoint3d(insertDpoint.x, insertDpoint.y, insertDpoint.z + lowSideHeight);
            //左上
            GeSegment3d TopLeftLinearElement = new GeSegment3d(topLeft_R, Helper.Extend_or_Contract(topLeft_R, new GePoint3d(topLeft_R.x + 1, topLeft_R.y, topLeft_R.z), 1000));
            GeSegment3d.getIntersectPointOfTwoSegments2D(ref fractionA, ref fractionB, insertDpoint, ptB, LinearElement_R, TopLeftLinearElement);
            GePoint3d topLeft_R2 = new GePoint3d(insertDpoint.x, insertDpoint.y, insertDpoint.z + lowSideHeight);
            //左下
            bottomWidthRight_R = insideSlope == 0 ? 0 : lowSideHeight * insideSlope;
            rightAngleSide = bottomWidthRight_R / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d bottomLeft_R2 = Helper.Extend_or_Contract(insertDpoint, tankBottomTopGePoint3ds[2], rightAngleSide);
            //右下
            bottomWidthLeft_R = outsideSlope == 0 ? 0 : lowSideHeight * outsideSlope;
            rightAngleSide = bottomWidthLeft_R / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d bottomRight_R2 = Helper.Extend_or_Contract(new GePoint3d(topRight_R2.x, topRight_R2.y, topRight_R2.z - lowSideHeight), tankBottomTopGePoint3ds[3], rightAngleSide);
            #endregion
            //顶面点
            GePoint3dCollection lstPt_Top = new GePoint3dCollection
            {
                topRight_R,
                topLeft_R,

                topLeft_R2,
                topRight_R2,
            };
            //底面点
            GePoint3dCollection lstPt_Bottom = new GePoint3dCollection
            {
                 bottomRight_R,
                bottomLeft_R,
                bottomLeft_R2,
                bottomRight_R2
            };
            BPGraphics graphics = Create(lstPt_Top, lstPt_Bottom);
            //graphics.save();

            return (graphics, bottomRight_R2);
        }

        /// <summary>
        /// 创建洞口左侧翼墙
        /// </summary>
        /// <param name="tankBottomTopGePoint3ds">槽底顶面点集</param>
        /// <param name="highEndHeight">高端高度</param>
        /// <param name="lowSideHeight">低端高度</param>
        /// <param name="topWidth">顶部宽</param>
        /// <param name="insideSlope">内坡坡度</param>
        /// <param name="outsideSlope">外坡坡度</param>
        /// <param name="angle">洞口夹角</param>
        /// <returns></returns>
        private static (BPGraphics, GePoint3d) CreateLeftCulvertRhoneBody(GePoint3dCollection tankBottomTopGePoint3ds, double highEndHeight, double lowSideHeight, double topWidth, double insideSlope, double outsideSlope, double tankBottomHeight, double angle)
        {
            GeSegment3d LinearElement_R = new GeSegment3d(tankBottomTopGePoint3ds[2], tankBottomTopGePoint3ds[3]);

            double bottomWidthLeft_R = outsideSlope == 0 ? 0 : highEndHeight * outsideSlope;

            #region 靠近洞口的点
            double rightAngleSide = bottomWidthLeft_R / Math.Cos((90 - angle) / 180 * Math.PI);
            //右上
            GePoint3d topRight_R = Helper.Extend_or_Contract(tankBottomTopGePoint3ds[1], tankBottomTopGePoint3ds[0], rightAngleSide);
            //左上
            rightAngleSide = topWidth / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d topLeft_R = Helper.Extend_or_Contract(topRight_R, tankBottomTopGePoint3ds[0], rightAngleSide);
            //左下
            double bottomWidthRight_R = insideSlope == 0 ? 0 : highEndHeight * insideSlope;
            rightAngleSide = bottomWidthRight_R / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d bottomLeft_R = Helper.Extend_or_Contract(topLeft_R, tankBottomTopGePoint3ds[0], rightAngleSide);
            bottomLeft_R.z = bottomLeft_R.z/* + tankBottomHeight*/;
            topRight_R.z = tankBottomTopGePoint3ds[1].z + highEndHeight;
            topLeft_R.z = tankBottomTopGePoint3ds[1].z + highEndHeight;
            //右下
            GePoint3d bottomRight_R = tankBottomTopGePoint3ds[1];
            #endregion

            #region 外侧点

            GeSegment3d TopRightLinearElement = new GeSegment3d(topRight_R, Helper.Extend_or_Contract(topRight_R, new GePoint3d(topRight_R.x + 1, topRight_R.y, topRight_R.z), 1000));
            double fractionA = 0;
            double fractionB = 0;
            GePoint3d insertDpoint = new GePoint3d(0, 0, 0);
            GePoint3d ptB = new GePoint3d(100, 0, 0);
            GeSegment3d.getIntersectPointOfTwoSegments2D(ref fractionA, ref fractionB, insertDpoint, ptB, LinearElement_R, TopRightLinearElement);
            //右上
            GePoint3d topRight_R2 = new GePoint3d(insertDpoint.x, insertDpoint.y, insertDpoint.z + lowSideHeight);
            //左上
            GeSegment3d TopLeftLinearElement = new GeSegment3d(topLeft_R, Helper.Extend_or_Contract(topLeft_R, new GePoint3d(topLeft_R.x + 1, topLeft_R.y, topLeft_R.z), 1000));
            GeSegment3d.getIntersectPointOfTwoSegments2D(ref fractionA, ref fractionB, insertDpoint, ptB, LinearElement_R, TopLeftLinearElement);
            GePoint3d topLeft_R2 = new GePoint3d(insertDpoint.x, insertDpoint.y, insertDpoint.z + lowSideHeight);
            //左下
            bottomWidthRight_R = insideSlope == 0 ? 0 : lowSideHeight * insideSlope;
            rightAngleSide = bottomWidthRight_R / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d bottomLeft_R2 = Helper.Extend_or_Contract(insertDpoint, tankBottomTopGePoint3ds[3], rightAngleSide);
            //右下
            bottomWidthLeft_R = outsideSlope == 0 ? 0 : lowSideHeight * outsideSlope;
            rightAngleSide = bottomWidthLeft_R / Math.Cos((90 - angle) / 180 * Math.PI);
            GePoint3d bottomRight_R2 = Helper.Extend_or_Contract(new GePoint3d(topRight_R2.x, topRight_R2.y, topRight_R2.z - lowSideHeight), tankBottomTopGePoint3ds[2], rightAngleSide);
            #endregion
            //顶面点
            GePoint3dCollection lstPt_Top = new GePoint3dCollection
            {
                topRight_R,
                topLeft_R,
                topLeft_R2,
                topRight_R2,

            };
            //底面点
            GePoint3dCollection lstPt_Bottom = new GePoint3dCollection
            {
                bottomRight_R,
                bottomLeft_R,
                bottomLeft_R2,
                bottomRight_R2
            };

            BPGraphics graphics = Create(lstPt_Top, lstPt_Bottom);
            //graphics.save();
            return (graphics, bottomRight_R2);
        }

        /// <summary>
        /// 槽底边坡点
        /// </summary>
        /// <param name="height">厚度</param>
        /// <param name="width">宽度</param>
        /// <param name="length">长度</param>
        /// <param name="slope">纵坡</param>
        private static GePoint3dCollection GetTankBottomPoints(double height, double width, double length, double slope, double angle)
        {
            double LeftLateralOffset = Math.Abs((width / 2) * Math.Tan((90 - angle) * Math.PI / 180));

            GePoint3d bottomInside_R = GePoint3d.createByZero();
            GePoint3d bottomInside_L = GePoint3d.createByZero();
            if (angle <= 90)
            {
                bottomInside_R = new GePoint3d(-LeftLateralOffset, -width / 2, 0);
                bottomInside_L = new GePoint3d(LeftLateralOffset, width / 2, 0);
            }
            else if (angle > 90)
            {
                bottomInside_R = new GePoint3d(LeftLateralOffset, -width / 2, 0);
                bottomInside_L = new GePoint3d(-LeftLateralOffset, width / 2, 0);
            }
            double b = bottomInside_R.y - bottomInside_R.x * slope;
            double nextY = (bottomInside_R.x + 1) * slope + b;
            GePoint3d nextGePoint3d_L = new GePoint3d(bottomInside_R.x + 1, -width / 2, nextY - bottomInside_R.y);
            GePoint3d nextGePoint3d_R = new GePoint3d(bottomInside_L.x + 1, width / 2, nextY - bottomInside_R.y);
            double newLength = Math.Sqrt(Math.Pow(length, 2) + Math.Pow(length * slope, 2));

            GePoint3d bottomOutside_L = Helper.Extend_or_Contract(bottomInside_R, nextGePoint3d_L, newLength);
            GePoint3d bottomOutside_R = Helper.Extend_or_Contract(bottomInside_L, nextGePoint3d_R, newLength);
            GePoint3dCollection tankBottomTopGePoint3ds = new GePoint3dCollection()
            {
                new GePoint3d(bottomInside_R.x, bottomInside_R.y, 0/*bottomInside_R.z*//*- height*/),
                new GePoint3d(bottomInside_L.x, bottomInside_L.y, 0/*bottomInside_L.z*//* - height*/) ,
                new GePoint3d(bottomOutside_R.x, bottomOutside_R.y, 0/*bottomOutside_R.z*//* - height*/),
                new GePoint3d(bottomOutside_L.x, bottomOutside_L.y, 0/*bottomOutside_L.z*//* - height*/)
            };

            return tankBottomTopGePoint3ds;
        }

        /// <summary>
        /// 创建洞口翼墙
        /// </summary>
        /// <param name="PtTops">顶面点</param>
        /// <param name="PtBottoms">底面点</param>
        /// <returns></returns>
        public static BPGraphics Create(GePoint3dCollection PtTops, GePoint3dCollection PtBottoms)
        {
            BPProject bPProject = BPApplication.getInstance().getProjectManager().getActiveProject();
            BPModelBase model = bPProject.getActiveModel();
            GeCurveArrayCollection curveArrays = new GeCurveArrayCollection();
            PolyfaceHandle polyHeader = PolyfaceHandle.createVariableSizeIndexed();
            //添加所有的顶点
            GePoint3dCollection pts_top = new GePoint3dCollection();
            for (int i = 0; i < PtTops.Count; i++)
            {
                pts_top.Add(PtTops[i]);
            }
            GePoint3dCollection pts_bottom = new GePoint3dCollection();
            for (int i = 0; i < PtBottoms.Count; i++)
            {
                pts_bottom.Add(PtBottoms[i]);
            }


            //构建顶面
            GeCurveArray curveArraytop = GeCurveArray.createLinestringArray(pts_top, BoundaryType.BOUNDARY_TYPE_Outer, true);
            curveArrays.Add(curveArraytop);

            //构建底面
            GeCurveArray curveArraybottom = GeCurveArray.createLinestringArray(pts_bottom, BoundaryType.BOUNDARY_TYPE_Outer, true);
            curveArrays.Add(curveArraybottom);

            //构建侧面
            for (int i = 0; i < pts_top.Count - 1; i++)
            {
                var pts = new GePoint3dCollection();
                pts.Add(pts_top[i]); pts.Add(pts_top[i + 1]); pts.Add(pts_bottom[i + 1]); pts.Add(pts_bottom[i]);
                GeCurveArray curveArray = GeCurveArray.createLinestringArray(pts, BoundaryType.BOUNDARY_TYPE_Outer, true);
                curveArrays.Add(curveArray);
            }

            //构建侧面 尾_首
            var pts1 = new GePoint3dCollection();
            pts1.Add(pts_top[pts_top.Count - 1]); pts1.Add(pts_top[0]); pts1.Add(pts_bottom[0]); pts1.Add(pts_bottom[pts_bottom.Count - 1]);
            GeCurveArray curveArray1 = GeCurveArray.createLinestringArray(pts1, BoundaryType.BOUNDARY_TYPE_Outer, true);
            curveArrays.Add(curveArray1);
            PolyfaceHandle polyface = PolyfaceHandle.createNewOne();
            BPMeshMeans.regionsGenerateMesh(polyface, curveArrays);
            BPGraphics bPGraphics = model.createPhysicalGraphics();

            bPGraphics.addPolyface(polyface);

            //bPGraphics.save();

            return bPGraphics;
        }
    }
}
